package com.tools.web.filter.gateway;

import com.tools.common.container.ConcurrentHashSet;
import com.tools.common.object.Force;
import com.tools.common.object.Note;
import com.tools.common.thread.TimePair;
import com.tools.common.thread.Timeunit;
import com.tools.db.cache.local.LocalCache;
import com.tools.web.WebKit;
import com.tools.web.interceptor.auth.AuthenticationManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Objects;
import java.util.Set;

/**
 * 使用 LocalCache 本地缓存实现的网关过滤器
 * */
@Note("使用 LocalCache 本地缓存实现的网关过滤器")
public final class LocalCacheGatewayManager extends AbsGatewayManager {

    @Note("LocalCache 本地缓存实例")
    private final LocalCache cache;

    @Note("已被禁用的 REST 接口列表")
    private ConcurrentHashSet<String> disabledURIs;

    @Note("是否禁用所有的 REST 接口")
    private boolean disabledAllRestApi = false;

    private static final Logger LOGGER = LoggerFactory.getLogger(LocalCacheGatewayManager.class);

    /* ********************************************************************************************
     *
     *         构造器
     *
     * *********************************************************************************************
     * */
    
    public LocalCacheGatewayManager(LocalCache cache, GatewaySource source) {
        this(cache, source, null);
    }
    
    public LocalCacheGatewayManager(LocalCache cache, GatewaySource source, AuthenticationManager authenticationManager) {
        super(source, authenticationManager);
        this.cache = Objects.requireNonNull(cache);
    }

    /* ********************************************************************************************
     *
     *         实现的方法
     *
     * *********************************************************************************************
     * */

    @Override
    protected Logger protected_getLogger() {
        return LOGGER;
    }

    @Override
    protected long protected_toSubclassDomainUnitTime(TimePair addBlackerThresholdTime) {
        return Timeunit.toMill(addBlackerThresholdTime);
    }

    @Override
    protected String protected_checkIfAddIPInBlacksAndGetTimeunitLabel(String clientIP) {
        long addBlackerThresholdTime = super.getAddBlackerThresholdTime();
        int addBlackerThreshold = super.getAddBlackerThreshold();
        String key = super.protected_getAddBlackSaveKey(clientIP);
        boolean[] result = new boolean[] { false };
        Force<Integer> forceHandler = new Force<Integer>(addBlackerThreshold, result, this, clientIP) {
            @Override
            public Integer force(Integer source) {
                int addBlackerThreshold = this.getParam(0, int.class);
                int newCount = source + 1;
                if(newCount < addBlackerThreshold) {
                    return newCount;
                }
                boolean[] result = this.getParam(1, boolean[].class);
                LocalCacheGatewayManager gatewayManager = this.getParam(2, LocalCacheGatewayManager.class);
                String clientIP = this.getParam(3, String.class);
                gatewayManager.addInIpBlacks(clientIP);
                result[0] = true;
                return newCount;
            }
        };
        this.cache.set(key, forceHandler, 1, addBlackerThresholdTime);
        if(!result[0]) {
            return null;
        }
        return Timeunit.MILL.getText();
    }

    @Override
    protected void protected_setDisabledAllURIProperty(boolean all) {
        this.disabledAllRestApi = all;
    }

    @Override
    protected int protected_initDisabledURIs(Set<String> disabledURIs) {
        this.disabledURIs = new ConcurrentHashSet<>(disabledURIs);
        return this.disabledURIs.size();
    }

    @Override
    protected boolean protected_isInDisabledURIs(String uri) {
        return this.disabledURIs.contains(uri);
    }

    @Override
    public LocalCacheGatewayManager addInDisabledURIs(String uri) {
        if(this.enabledDisabledURIs()) {
            if("*".equals(uri)) this.disabledAllRestApi = true;
            else this.disabledURIs.add(WebKit.uriAddServerContextPath(uri, super.getServerContextPath()));
        }
        return this;
    }

    @Override
    public LocalCacheGatewayManager addAllInDisabledURIs(String... uris) {
        if(uris == null || uris.length == 0) return this;
        if(this.enabledDisabledURIs()) {
            if(protected_changeAll(true, uris) != null) this.disabledAllRestApi = true;
            for(String uri : uris) {
                this.disabledURIs.add(WebKit.uriAddServerContextPath(uri, super.getServerContextPath()));
            }
        }
        return this;
    }

    @Override
    public LocalCacheGatewayManager addAllInDisabledURIs(Iterable<String> uris) {
        if(this.enabledDisabledURIs()) {
            if(protected_changeAll(true, uris) != null) this.disabledAllRestApi = true;
            for(String uri : uris) {
                this.disabledURIs.add(WebKit.uriAddServerContextPath(uri, super.getServerContextPath()));
            }
        }
        return this;
    }

    @Override
    public LocalCacheGatewayManager removeFromDisabledURIs(String uri) {
        if(this.enabledDisabledURIs()) {
            if("*".equals(uri)) this.disabledAllRestApi = false;
            else this.disabledURIs.remove(WebKit.uriAddServerContextPath(uri, super.getServerContextPath()));
        }
        return this;
    }

    @Override
    public LocalCacheGatewayManager removeAllFromDisabledURIs(String... uris) {
        if(uris == null || uris.length == 0) return this;
        if(this.enabledDisabledURIs()) {
            if(protected_changeAll(false, uris) != null) this.disabledAllRestApi = false;
            this.disabledURIs.removeAll(uris);
        }
        return this;
    }

    @Override
    public LocalCacheGatewayManager removeAllFromDisabledURIs(Iterable<String> uris) {
        if(this.enabledDisabledURIs()) {
            if(protected_changeAll(false, uris) != null) this.disabledAllRestApi = false;
            this.disabledURIs.removeAll(uris);
        }
        return this;
    }

    @Override
    public LocalCacheGatewayManager clearDisabledURIs() {
        if(this.enabledDisabledURIs()) {
            this.disabledURIs.clear();
        }
        return this;
    }

    @Override
    public boolean isInDisabledURIs(String uri) {
        if(this.enabledDisabledURIs()) {
            if(this.disabledAllRestApi) return true;
            return this.disabledURIs.contains(WebKit.uriAddServerContextPath(uri, super.getServerContextPath()));
        }
        return false;
    }

    @Override
    public boolean isAllInDisabledURIs(String... uris) {
        if(uris == null || uris.length == 0) return false;
        if(this.enabledDisabledURIs()) {
            if(this.disabledAllRestApi) return true;
            for(String uri : uris) {
                if(!this.disabledURIs.contains(WebKit.uriAddServerContextPath(uri, super.getServerContextPath()))) return false;
            }
            return true;
        }
        return false;
    }

    @Override
    public boolean isAllInDisabledURIs(Iterable<String> uris) {
        if(protected_iterableIsEmpty(uris)) return false;
        if(this.enabledDisabledURIs()) {
            if(!this.disabledAllRestApi) {
                for(String uri : uris) {
                    if(!this.disabledURIs.contains(WebKit.uriAddServerContextPath(uri, super.getServerContextPath()))) return false;
                }
            }
            return true;
        }
        return false;
    }

    @Override
    public boolean isAnyInDisabledURIs(String... uris) {
        if(uris == null || uris.length == 0) return false;
        if(this.enabledDisabledURIs()) {
            if(this.disabledAllRestApi) return true;
            for(String uri : uris) {
                if(this.disabledURIs.contains(WebKit.uriAddServerContextPath(uri, super.getServerContextPath()))) return true;
            }
            return false;
        }
        return false;
    }

    @Override
    public boolean isAnyInDisabledURIs(Iterable<String> uris) {
        if(protected_iterableIsEmpty(uris)) return false;
        if(this.enabledDisabledURIs()) {
            if(!this.disabledAllRestApi) {
                for(String uri : uris) {
                    if(this.disabledURIs.contains(WebKit.uriAddServerContextPath(uri, super.getServerContextPath()))) return true;
                }
                return false;
            }
            return true;
        }
        return false;
    }

    /* ********************************************************************************************
     *
     *         重写的方法
     *
     * *********************************************************************************************
     * */


    @Override
    public LocalCacheGatewayManager addInProxyWhites(String remote) {
        super.addInProxyWhites(remote);
        return this;
    }

    @Override
    public LocalCacheGatewayManager addAllInProxyWhites(String... remotes) {
        super.addAllInProxyWhites(remotes);
        return this;
    }

    @Override
    public LocalCacheGatewayManager addAllInProxyWhites(Iterable<String> remotes) {
        super.addAllInProxyWhites(remotes);
        return this;
    }

    @Override
    public LocalCacheGatewayManager removeFromProxyWhites(String remote) {
        super.removeFromProxyWhites(remote);
        return this;
    }

    @Override
    public LocalCacheGatewayManager removeAllFromProxyWhites(String... remotes) {
        super.removeAllFromProxyWhites(remotes);
        return this;
    }

    @Override
    public LocalCacheGatewayManager removeAllFromProxyWhites(Iterable<String> remotes) {
        super.removeAllFromProxyWhites(remotes);
        return this;
    }

    @Override
    public LocalCacheGatewayManager clearProxyWhites() {
        super.clearProxyWhites();
        return this;
    }

    @Override
    public LocalCacheGatewayManager addInIpWhites(String clientIP) {
        super.addInIpWhites(clientIP);
        return this;
    }

    @Override
    public LocalCacheGatewayManager addAllInIpWhites(String... clientIPs) {
        super.addAllInIpWhites(clientIPs);
        return this;
    }

    @Override
    public LocalCacheGatewayManager addAllInIpWhites(Iterable<String> clientIPs) {
        super.addAllInIpWhites(clientIPs);
        return this;
    }

    @Override
    public LocalCacheGatewayManager removeFromIpWhites(String clientIP) {
        super.removeFromIpWhites(clientIP);
        return this;
    }

    @Override
    public LocalCacheGatewayManager removeAllFromIpWhites(String... clientIPs) {
        super.removeAllFromIpWhites(clientIPs);
        return this;
    }

    @Override
    public LocalCacheGatewayManager removeAllFromIpWhites(Iterable<String> clientIPs) {
        super.removeAllFromIpWhites(clientIPs);
        return this;
    }

    @Override
    public LocalCacheGatewayManager clearIpWhites() {
        super.clearIpWhites();
        return this;
    }

    @Override
    public LocalCacheGatewayManager addInIpBlacks(String clientIP) {
        super.addInIpBlacks(clientIP);
        return this;
    }

    @Override
    public LocalCacheGatewayManager addInIpBlacks(String... clientIPs) {
        super.addInIpBlacks(clientIPs);
        return this;
    }

    @Override
    public LocalCacheGatewayManager addInIpBlacks(Iterable<String> clientIPs) {
        super.addInIpBlacks(clientIPs);
        return this;
    }

    @Override
    public LocalCacheGatewayManager removeFromIpBlacks(String clientIP) {
        super.removeFromIpBlacks(clientIP);
        return this;
    }

    @Override
    public LocalCacheGatewayManager removeAllFromIpBlacks(String... clientIPs) {
        super.removeAllFromIpBlacks(clientIPs);
        return this;
    }

    @Override
    public LocalCacheGatewayManager removeAllFromIpBlacks(Iterable<String> clientIPs) {
        super.removeAllFromIpBlacks(clientIPs);
        return this;
    }

    @Override
    public LocalCacheGatewayManager clearIpBlacks() {
        super.clearIpBlacks();
        return this;
    }
}
